/* 
 * CS:APP Data Lab 
 * 
 * <Please put your name and userid here>
 * 
 * bits.c - Source file with your solutions to the Lab.
 *          This is the file you will hand in to your instructor.
 *
 * WARNING: Do not include the <stdio.h> header; it confuses the dlc
 * compiler. You can still use printf for debugging without including
 * <stdio.h>, although you might get a compiler warning. In general,
 * it's not good practice to ignore compiler warnings, but in this
 * case it's OK.  
 */

#if 0
/*
 * Instructions to Students:
 *
 * STEP 1: Read the following instructions carefully.
 */

You will provide your solution to the Data Lab by
editing the collection of functions in this source file.

INTEGER CODING RULES:
 
  Replace the "return" statement in each function with one
  or more lines of C code that implements the function. Your code 
  must conform to the following style:
 
  int Funct(arg1, arg2, ...) {
      /* brief description of how your implementation works */
      int var1 = Expr1;
      ...
      int varM = ExprM;

      varJ = ExprJ;
      ...
      varN = ExprN;
      return ExprR;
  }

  Each "Expr" is an expression using ONLY the following:
  1. Integer constants 0 through 255 (0xFF), inclusive. You are
      not allowed to use big constants such as 0xffffffff.
  2. Function arguments and local variables (no global variables).
  3. Unary integer operations ! ~
  4. Binary integer operations & ^ | + << >>
    
  Some of the problems restrict the set of allowed operators even further.
  Each "Expr" may consist of multiple operators. You are not restricted to
  one operator per line.

  You are expressly forbidden to:
  1. Use any control constructs such as if, do, while, for, switch, etc.
  2. Define or use any macros.
  3. Define any additional functions in this file.
  4. Call any functions.
  5. Use any other operations, such as &&, ||, -, or ?:
  6. Use any form of casting.
  7. Use any data type other than int.  This implies that you
     cannot use arrays, structs, or unions.

 
  You may assume that your machine:
  1. Uses 2s complement, 32-bit representations of integers.
  2. Performs right shifts arithmetically.
  3. Has unpredictable behavior when shifting an integer by more
     than the word size.

EXAMPLES OF ACCEPTABLE CODING STYLE:
  /*
   * pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
   */
  int pow2plus1(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     return (1 << x) + 1;
  }

  /*
   * pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
   */
  int pow2plus4(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     int result = (1 << x);
     result += 4;
     return result;
  }

FLOATING POINT CODING RULES

For the problems that require you to implent floating-point operations,
the coding rules are less strict.  You are allowed to use looping and
conditional control.  You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants.

You are expressly forbidden to:
  1. Define or use any macros.
  2. Define any additional functions in this file.
  3. Call any functions.
  4. Use any form of casting.
  5. Use any data type other than int or unsigned.  This means that you
     cannot use arrays, structs, or unions.
  6. Use any floating point data types, operations, or constants.


NOTES:
  1. Use the dlc (data lab checker) compiler (described in the handout) to 
     check the legality of your solutions.
  2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
     that you are allowed to use for your implementation of the function. 
     The max operator count is checked by dlc. Note that '=' is not 
     counted; you may use as many of these as you want without penalty.
  3. Use the btest test harness to check your functions for correctness.
  4. Use the BDD checker to formally verify your functions
  5. The maximum number of ops for each function is given in the
     header comment for each function. If there are any inconsistencies 
     between the maximum ops in the writeup and in this file, consider
     this file the authoritative source.

/*
 * STEP 2: Modify the following functions according the coding rules.
 * 
 *   IMPORTANT. TO AVOID GRADING SURPRISES:
 *   1. Use the dlc compiler to check that your solutions conform
 *      to the coding rules.
 *   2. Use the BDD checker to formally verify that your solutions produce 
 *      the correct answers.
 */


#endif
/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
  
  int test1,test2,test3;
  test1=(!!x);                // 将x转换为布尔值（0或1）
  test1=(test1<<31)>>31;      // 将布尔值扩展为全0或全1的32位掩码
  test2=!x;                   // x为0时得到1，否则得到0
  test2=(test2<<31)>>31;      // 同样扩展为32位掩码

  test3=(test1&y)+(test2&z);  // 当x非0时选择y，当x为0时选择z
  return test3;
}

/* 
 * isNonNegative - return 1 if x >= 0, return 0 otherwise 
 *   Example: isNonNegative(-1) = 0.  isNonNegative(0) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 3
 */
int isNonNegative(int x) {
  /* 
   * 判断x是否为非负数
   * 思路：在二进制补码表示中，最高位为符号位
   * 通过右移31位，可以得到符号位扩展的结果
   * 对于负数，结果为0xFFFFFFFF；对于非负数，结果为0x00000000
   */
  int test1=x>>31;  // 算术右移31位，获取符号位并扩展到32位
  test1=!test1;     // 对结果取非，使非负数返回1，负数返回0
  return test1;
}

/* 
 * isGreater - if x > y  then return 1, else return 0 
 *   Example: isGreater(4,5) = 0, isGreater(5,4) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isGreater(int x, int y) {
  int equalval=x^y;         // 相同位为0，不同位为1，用于判断符号是否相同
  int subval=x+(~(y+1)+1);  // 计算x-y-1，避免溢出
  int result=(((~subval)&(~equalval))+(y&equalval))>>31;  // 组合处理符号相同和不同的情况
                                                          // (~subval)&(~equalval)处理符号相同的情况
                                                          // y&equalval处理符号不同的情况
  result=result&0x01;       // 取结果的最低位，确保返回值为0或1
  return result;
}

/* 
 * absVal - absolute value of x
 *   Example: absVal(-1) = 1.
 *   You may assume -TMax <= x <= TMax
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 10
 *   Rating: 4
 */
int absVal(int x) {
  
  int result,signbit;
  signbit=x>>31;  // 获取符号位并扩展为32位掩码（正数为全0，负数为全1）
  
  // 使用掩码选择：
  // 当x为正数时：(~signbit)&x 返回x，signbit&(~x+1)返回0
  // 当x为负数时：(~signbit)&x 返回0，signbit&(~x+1)返回-x
  result=((~signbit)&x)+(signbit&(~x+1));
  
  return result;
}

/*
 * isPower2 - returns 1 if x is a power of 2, and 0 otherwise
 *   Examples: isPower2(5) = 0, isPower2(8) = 1, isPower2(0) = 0
 *   Note that no negative number is a power of 2.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 4
 */
int isPower2(int x) {
  
  int signbit=(x>>31)&0x01;                  // 获取符号位
  int signbit2=((x+~0x00)>>31)&0x01;         // 获取x-1的符号位
  int abzero=signbit+(signbit2&(~signbit));  // 判断x是否大于0，大于0时为0，否则为1
  int nature=x&(x+~0x00);                    // 检查x & (x-1)是否为0
  int result=abzero+nature;                  // 两个条件都满足（都为0）时，x是2的幂
  return !result;                            // 取反，使2的幂返回1，其他返回0
}

/* 
 * float_neg - Return bit-level equivalent of expression -f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representations of
 *   single-precision floating point values.
 *   When argument is NaN, return argument.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 10
 *   Rating: 2
 */
unsigned float_neg(unsigned uf) {
  
  unsigned result;
  int elsign=uf&0x7fffffff;    // 获取除符号位外的所有位
  int exp=elsign>>23;          // 提取阶码字段
  
  // 检查是否为NaN：阶码全为1且尾数不全为0
  if((!(exp^0xff))&&(elsign^0x7f800000))
    return uf;  // 如果是NaN，直接返回原值
  
  result=uf^0x80000000;  // 否则，翻转符号位
  return result;
}

/* 
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_i2f(int x) {
  
  int signbit,highbit,exp,fracbits,flag;
  unsigned temp,result;
  
  if(!x)
    return x;             // 特殊处理0的情况
  
  signbit=(x>>31)&0x01;   // 提取符号位
  if(signbit)
    x=~x+1;              // 如果是负数，转换为正数处理
  
  highbit=0;
  temp=x;
  while(!(temp&0x80000000)) {
    temp<<=1;
    highbit++;
  }                       // 找到最高有效位的位置
  
  temp=temp<<1;
  exp=127+31-highbit;     // 计算阶码值：偏置值(127) + 指数值
  fracbits=31-highbit;    // 计算尾数的位数
  
  flag=0;                 // 处理舍入
  if((temp&0x1ff)>0x100||(temp&0x3ff)==0x300)  // 如果舍弃的位大于中间值，向上舍入，如果舍弃的位等于中间值且最低保留位为1，向偶数舍入
    flag=1;

  // 组合符号位、阶码和尾数，构造浮点数表示
  result=(signbit<<31)+(exp<<23)+(temp>>9)+flag;
  
  return result;
}